package com.ilxqx.framework.security.config;

import com.ilxqx.framework.security.filter.AccessKeyFilter;
import com.ilxqx.framework.security.filter.GeeTestValidationFilter;
import com.ilxqx.framework.security.handler.*;
import com.ilxqx.framework.security.validation.Validation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * SpringSecurity配置
 * @author venus
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final FrameworkAuthenticationSuccessHandler frameworkAuthenticationSuccessHandler;
    private final FrameworkAuthenticationFailureHandler frameworkAuthenticationFailureHandler;
    private final SecurityConfigProperties securityConfigProperties;
    private final FrameworkLogoutSuccessHandler frameworkLogoutSuccessHandler;
    private final FrameworkInvalidSessionStrategy frameworkInvalidSessionStrategy;
    private final FrameworkAccessDeniedHandler frameworkAccessDeniedHandler;
    private final Validation geeTestValidation;

    @Autowired
    public SecurityConfig(FrameworkAuthenticationSuccessHandler frameworkAuthenticationSuccessHandler, FrameworkAuthenticationFailureHandler frameworkAuthenticationFailureHandler, SecurityConfigProperties securityConfigProperties, FrameworkLogoutSuccessHandler frameworkLogoutSuccessHandler, FrameworkInvalidSessionStrategy frameworkInvalidSessionStrategy, Validation geeTestValidation, FrameworkAccessDeniedHandler frameworkAccessDeniedHandler) {
        this.frameworkAuthenticationSuccessHandler = frameworkAuthenticationSuccessHandler;
        this.frameworkAuthenticationFailureHandler = frameworkAuthenticationFailureHandler;
        this.securityConfigProperties = securityConfigProperties;
        this.frameworkLogoutSuccessHandler = frameworkLogoutSuccessHandler;
        this.frameworkInvalidSessionStrategy = frameworkInvalidSessionStrategy;
        this.frameworkAccessDeniedHandler = frameworkAccessDeniedHandler;
        this.geeTestValidation = geeTestValidation;
    }

    /**
     * 配置security规则
     * @param http security对象
     * @throws Exception 异常
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .addFilterBefore(new GeeTestValidationFilter(this.securityConfigProperties, this.frameworkAuthenticationFailureHandler, this.geeTestValidation), UsernamePasswordAuthenticationFilter.class)
            // 添加key过滤
            .addFilterAfter(new AccessKeyFilter(), FilterSecurityInterceptor.class)
            // 禁止使用记住我
            .rememberMe().disable()
            // 表单登录
            .formLogin()
            .loginPage(securityConfigProperties.getLoginPage())
            .loginProcessingUrl(securityConfigProperties.getLoginProcessingUrl())
            .usernameParameter(securityConfigProperties.getUsernameParameter())
            .passwordParameter(securityConfigProperties.getPasswordParameter())
            .successHandler(frameworkAuthenticationSuccessHandler)
            .failureHandler(frameworkAuthenticationFailureHandler)
            .and()
            // 登出配置
            .logout()
            .logoutUrl(securityConfigProperties.getLogoutUrl())
            .logoutSuccessHandler(frameworkLogoutSuccessHandler)
            .clearAuthentication(true)
            .and()
            // session配置
            .sessionManagement()
            .invalidSessionStrategy(frameworkInvalidSessionStrategy)
            .and()
            .exceptionHandling()
            .accessDeniedHandler(this.frameworkAccessDeniedHandler)
            .and()
            // 访问授权
            .authorizeRequests()
            .antMatchers(securityConfigProperties.getAllowedUrls())
            .permitAll()
            .antMatchers(securityConfigProperties.getAuthenticatedUrls())
            .authenticated()
            .anyRequest()
            .access("isAuthenticated() && @accessService.canAccess(request)")
            .and()
            .headers()
            .frameOptions()
            .disable()
            .and()
            .cors()
            .and()
            .csrf()
            .disable();
    }

}
